/**
 * Collaborative Story Development Web Application (CSDApp) Copyright Anton
 * Strack 2014
 *
 * This file is part of Collaborative Story Development Application (CSDApp).
 *
 * CSDApp is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or any later version.
 *
 * CSDApp is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * CSDApp. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package csdwa;

import java.sql.Connection;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * This class handles the routing selection process and maintains the varius
 * managers used by the controller classes. Additionally, as this class
 * represents the entry point and exit point of the specific csdwa application
 * code, it inititiates the authentication and authorization as well as
 * attaching bean objects used by the jsps.
 *
 * @author Anton Strack
 */
public class ResourceRequestDelegator {

    /**
     * The csdwa specific request object
     */
    private CsdwaRequest request;
    /**
     * The httpServeletResponse object
     */
    private HttpServletResponse response;
    //  private Datasource ds;
    private UserHistoryManager userHistoryManager;
    private TaskManager taskManager;
    private NotificationManager notificationManager;
    private RelationshipManager relationshipManager;
    private PostManager postManager;
    private Connection conn;

    public ResourceRequestDelegator(Connection conn) {

        this.userHistoryManager = new UserHistoryManager(conn);
        this.taskManager = new TaskManager(conn);
        this.notificationManager = new NotificationManager(conn);
        this.relationshipManager = new RelationshipManager(conn);
        this.postManager = new PostManager(conn);
        this.conn = conn;
    }

    /**
     * The initial entry point into the application
     *
     * @param request the request initiated by the end user.
     * @param response the response object for the request.
     * @return the processed request.
     */
    public HttpServletRequest processRequest(HttpServletRequest request, HttpServletResponse response) {
        InfoAggregator infoAggregator = InfoAggregator.getInstance();
        String result = "/index.jsp"; // default view
        String requestType = request.getParameter("rtype");
        CsdwaRequest req = new Request(request);
        if (requestType != null && requestType.isEmpty() == false) {
            if (requestType.equalsIgnoreCase(RequestType.ASYNC.toString())) {
                req.setRequestType(RequestType.ASYNC);
            } else {
                req.setRequestType(RequestType.SYNC);
            }
        } else {
            req.setRequestType(RequestType.SYNC);
        }
        this.response = response;

        String form_submit = req.getFormId();//request.getParameter("formSubmit");
        if (form_submit != null && form_submit.isEmpty() == false) {
            // form actions are authenticated twice, once to get to the page with the form, and then again when submitting the form.
            // this code sets up the primary action and resource so they can be authenticated
            String[] actionResource = form_submit.split("-");
            if (actionResource.length == 2) {
                req.setPrimaryActionTypeName(actionResource[0]);
                req.setPrimaryResourceTypeName(actionResource[1]);
            } else {
                req.setPrimaryActionTypeName("view");
                req.setPrimaryResourceTypeName("site");
            }
        }
        /*
         * Start the core processing code.
         */
        req = this.processRequest(req);
        /*
         * Request is complete. Now attach the varius resources to the outgoing request object for the jsp pages.
         */

        /*
         * Attach the latest comments to the request object for the jsp page to display on the site side bar.
         */
        CommentDao cdao = DaoFactory.makeCommentDao(this.conn);
        cdao.setUseRelatedMarkers(true);
        cdao.setMarker(QueryMarker.LIMIT, "LIMIT " + Configuration.getRecentCommentMaxCount());
        cdao.usingQueryMarkers.add(QueryMarker.LIMIT);
        cdao.selectBeans();
        req.setAttribute("recentComments", cdao.getBeans());
        /*
         * Special handling for the front page. here apply the visual indicators
         */
        if ("/index.jsp".equalsIgnoreCase(req.getView())) {
            // -- considering just having sidebar items for front page and just comments on every page
            req = this.getPostManager().attachUserRecentPosts(req, infoAggregator.getResourceTypeId("plot"));
            req = this.getPostManager().attachUserRecentPosts(req, infoAggregator.getResourceTypeId("character"));
            req = this.getPostManager().attachUserRecentPosts(req, infoAggregator.getResourceTypeId("location"));
            req = this.getPostManager().attachUserRecentPosts(req, infoAggregator.getResourceTypeId("dialog"));
            // add visual post indicators now - con probably make this done in one sql query per domain type
            req = this.frontPagePostHistories(req, "recentplots");
            req = this.frontPagePostHistories(req, "recentcharacters");
            req = this.frontPagePostHistories(req, "recentlocations");
            req = this.frontPagePostHistories(req, "recentdialogs");
        }

        /*
         * Attach the latest user notifications to the request object so that the jsp pages can display it on the user side bar.
         */
        req = this.getNotificationManager().attachUserNotifications(req);
        /*
         * Attach the latest user pending tasks to the request object so that the jsp pages can display it on the user side bar.
         */
        req = this.getTaskManager().attachUserPendingTasks(req);
        /*
         * Attach the latest user history to the request object so that the jsp pages can display it on the user side bar.
         */
        // since the user has now links to view user histories, might remove this. comment out for now
        // req = this.getUserHistoryManager().attachUserPostHistories(req);

        /*
         * Obfuscate content within posts if the user is a guest.
         */
        req = this.getPostManager().obfuscatePosts(req);

        request = req.getRequest();// return the fully processed request back as an HttpServletRequest
        return request;
    }

    public CsdwaRequest frontPagePostHistories(CsdwaRequest request, String listName) {
        if (request.getAttribute(listName) != null) {
            List<CsdwaRecordable> posts;// = new ArrayList<CsdwaRecordable>();
            posts = this.userHistoryManager.processUserPostHistory((List<CsdwaRecordable>) request.getAttribute(listName), request.getCurrentUser());
        }
        return request;
    }

    /**
     * This method provides the HttpServlet implementing class the means to get
     * the processed response.
     *
     * @return the HttpServletResponse object.
     */
    public HttpServletResponse getProcessedResponse() {
        return this.response;
    }

    /**
     * The core processing entry point to the system. This code handles the
     * authentication and authorization and delegates the request to the proper
     * controller.
     *
     * @param request the CsdwaRequest object that represents and contains the
     * request code and resources.
     * @return the processed request.
     */
    public CsdwaRequest processRequest(CsdwaRequest request) {
        CsdwaController controller;
        int id = request.getPrimaryResourceId();
        // authenticate and authorize action on resource
        AccessControl ac = new AccessControl(conn);
        User user = ac.authenticate(request.getRequest());

        String primaryResourceTypeName = request.getPrimaryResourceTypeName();
        String primaryActionTypeName = request.getPrimaryActionTypeName();
        if (primaryResourceTypeName == null || primaryResourceTypeName.isEmpty()) {
            primaryResourceTypeName = "site";
        }
        if (primaryActionTypeName == null || primaryActionTypeName.isEmpty()) {
            primaryActionTypeName = "view";
        }

        int resourceTypeId = InfoAggregator.getInstance().getResourceTypeId(primaryResourceTypeName);
        int actionId = InfoAggregator.getInstance().getActionTypeId(primaryActionTypeName);
        int resourceId = request.getPrimaryResourceId();

        boolean authorized = ac.isAuthorized(user, actionId, resourceTypeId, resourceId);

        if (authorized == true) {
            controller = ControllerFactory.getController(resourceTypeId, conn);
        } else {
            controller = ControllerFactory.makeSiteController(conn);
            request.setMessage("You are not authorized to:" + request.getPrimaryActionTypeName() + " " + request.getPrimaryResourceTypeName());
            request.setMessageType("error");
        }
        // send the request the the controller that will handle the specifics of the request.
        request = controller.handleRequest(request);
        return request;
    }

    /**
     * @return the userHistoryManager
     */
    public UserHistoryManager getUserHistoryManager() {
        return userHistoryManager;
    }

    /**
     * @param userHistoryManager the userHistoryManager to set
     */
    public void setUserHistoryManager(UserHistoryManager userHistoryManager) {
        this.userHistoryManager = userHistoryManager;
    }

    /**
     * @return the taskManager
     */
    public TaskManager getTaskManager() {
        return taskManager;
    }

    /**
     * @param taskManager the taskManager to set
     */
    public void setTaskManager(TaskManager taskManager) {
        this.taskManager = taskManager;
    }

    /**
     * @return the notificationManager
     */
    public NotificationManager getNotificationManager() {
        return notificationManager;
    }

    /**
     * @param notificationManager the notificationManager to set
     */
    public void setNotificationManager(NotificationManager notificationManager) {
        this.notificationManager = notificationManager;
    }

    /**
     * @return the relationshipManager
     */
    public RelationshipManager getRelationshipManager() {
        return relationshipManager;
    }

    /**
     * @param relationshipManager the relationshipManager to set
     */
    public void setRelationshipManager(RelationshipManager relationshipManager) {
        this.relationshipManager = relationshipManager;
    }

    /**
     * @return the postManager
     */
    public PostManager getPostManager() {
        return postManager;
    }

    /**
     * @param postManager the postManager to set
     */
    public void setPostManager(PostManager postManager) {
        this.postManager = postManager;
    }
}
